package cgl.narada.samples.secureAV;

/**
 * This class is adapted from cgl.narada.samples.rtp.NBRTPTransmitter.
 * It uses NBMediaConnector to transmit stream.
 *
 * @author Hasan Bulut  - hbulut@indiana.edu
 * Community Grids Lab., Indiana University
 * @version 1.0
 */
import java.awt.Dimension;
import java.security.PrivateKey;
import java.util.Properties;

import javax.media.CaptureDeviceInfo;
import javax.media.CaptureDeviceManager;
import javax.media.Format;
import javax.media.MediaLocator;
import javax.media.format.AudioFormat;
import javax.media.format.VideoFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;
import javax.media.rtp.RTPConnector;
import javax.media.rtp.RTPManager;
import javax.media.rtp.SendStream;

import cgl.narada.samples.rtp.MediaCapturer;
import cgl.narada.service.ServiceException;
import cgl.narada.service.client.EventProducer;
import cgl.narada.service.security.kmc.messages.SecureTopicKeyResponse;
import cgl.narada.util.SystemInit;

public class NBMediaTransmitter {

    private RTPManager rtpManager = null;
    private DataSource dataSource = null;
    private RTPConnector connector = null;

    public NBMediaTransmitter(RTPConnector connector) {
        this.connector = connector;
    }

    public void setDataSource(DataSource ds) {

        if (ds == null) {
            System.out.println("DataSource is null.");
            return;
        }

        if (this.dataSource != null) {
            System.out.println("datasource is already set.");
            return;
        }
        this.dataSource = ds;
    }

    public void close() {

        if (dataSource != null) {
            dataSource.disconnect();
        }

        if (rtpManager != null) {
            rtpManager.removeTargets("Session ended.");
            rtpManager.dispose();
            rtpManager = null;
        }
    }

    public String start() {
        try {
            rtpManager = RTPManager.newInstance();
            System.out.println("Before initializing RTP Manager");
            rtpManager.initialize(connector);
            System.out.println("After initializing RTP Manager");
            SendStream sendStream = rtpManager.createSendStream(dataSource, 0);
            sendStream.start();
            System.out.println("Started transmitting data with the ssrc: "
                    + sendStream.getSSRC());
        } catch (javax.media.format.UnsupportedFormatException e) {
            System.out
                    .println(this.getClass().getName()
                            + "  Exception while trying to initialize rtp manager. The message is: "
                            + e.getMessage());
            System.out.println(this.getClass().getName()
                    + "  the failed exception is: " + e.getFailedFormat());
            return e.getMessage();
        } catch (Exception e) {
            return e.getMessage();
        }
        return null;
    }

    public static void main(String args[]) throws Exception {
        // if ((args.length < 4) || (args.length > 5)) {
        // printUsage();
        // return;
        // }

        SystemInit.init();
        
        String brokerIP = args[0];
        int brokerPort = Integer.parseInt(args[1]);
        int topicNumber = Integer.parseInt(args[2]);
        String commType = args[3];

        boolean formath263 = true;
        System.out.println("input size: " + args.length);
        if (args.length == 5) {
            formath263 = false;
        }

        // default values
        String keyAlg = "AES";
        int keySize = 128, timeout1 = 5, timeout2 = 2;
        String sig = "SHA1withRSA", mode = "CBC", padding = "PKCS7Padding";

        boolean enableAudio = false, enableVideo = false;

        if (args.length > 5)
            keyAlg = args[5];
        if (args.length > 6)
            keySize = Integer.parseInt(args[6]);
        if (args.length > 7)
            timeout1 = Integer.parseInt(args[7]);
        if (args.length > 8)
            timeout2 = Integer.parseInt(args[8]);
        if (args.length > 9)
            sig = args[9];
        if (args.length > 10)
            mode = args[10];
        if (args.length > 11)
            padding = args[11];

        if (args.length > 12)
            enableAudio = args[12].equals("1") ? true : false;

        if (args.length > 13)
            enableVideo = args[13].equals("1") ? true : false;

        ContentDescriptor cd = new ContentDescriptor(ContentDescriptor.RAW_RTP);
        NBMediaTransmitter cta = null;
        NBMediaTransmitter ctv = null;
        Properties props = new Properties();
        props.put("hostname", brokerIP);
        props.put("portnum", "" + brokerPort);

        // AUDIO...

        if (enableAudio) {
            MediaLocator mla = new MediaLocator("dsound://");
            AudioFormat af = new AudioFormat(AudioFormat.ULAW_RTP, 8000.0, 8,
                    1, AudioFormat.NOT_SPECIFIED, AudioFormat.UNSIGNED);
            MediaCapturer mca = new MediaCapturer(mla, cd, af);
            DataSource dataSourcea = mca.getDataSource();
            System.out.println("Starting Audio");
            NBMediaConnector connectora = new NBMediaConnector(brokerIP,
                    brokerPort, 2, topicNumber + 2);

            String control = connectora.getControlTopic();
            String data = connectora.getDataTopic();

            System.out.println("Generating topics and Security Tokens");

            SecureTopicsKeyGenerator stkGenA = new SecureTopicsKeyGenerator(
                    data, control, "c1", brokerIP, "" + brokerPort, commType);

            stkGenA.generateTopics(keyAlg, keySize, timeout1, timeout2);
            connectora.setEncryptedDataTopicUUID(stkGenA.topicUUIDData);
            connectora.setEncryptedControlTopicUUID(stkGenA.topicUUIDControl);

            try {
                connectora.initializeBrokerCommunications(props, commType);
                connectora.initializeTransmitter(sig, mode, padding,
                        stkGenA.topicUUIDData, stkGenA.stkData,
                        stkGenA.topicUUIDControl, stkGenA.stkControl,
                        stkGenA.c_priv);
                // connector.initializeReceiver();
            } catch (ServiceException ex) {
                ex.printStackTrace();
            }
            cta = new NBMediaTransmitter(connectora);
            cta.setDataSource(dataSourcea);
        }

        // VIDEO...
        if (enableVideo) {
            MediaLocator mlv = getMediaLocator();
            VideoFormat vf1 = new VideoFormat(VideoFormat.H261_RTP,
                    new Dimension(352, 288), Format.NOT_SPECIFIED, null,
                    Format.NOT_SPECIFIED);
            // VideoFormat vf1 = new VideoFormat(VideoFormat.H261_RTP);
            VideoFormat vf2 = new VideoFormat(VideoFormat.H263_RTP);
            VideoFormat vf = null;
            if (formath263) {
                vf = vf2;
            } else {
                vf = vf1;
            }

            MediaCapturer mcv = new MediaCapturer(mlv, cd, vf);
            DataSource dataSourcev = mcv.getDataSource();
            System.out.println("Starting Video");
            NBMediaConnector connectorv = new NBMediaConnector(brokerIP,
                    brokerPort, 2, topicNumber);

            String control = connectorv.getControlTopic();
            String data = connectorv.getDataTopic();

            System.out.println("Generating topics and Security Tokens");

            SecureTopicsKeyGenerator stkGenV = new SecureTopicsKeyGenerator(
                    data, control, "c1", brokerIP, "" + brokerPort, commType);

            stkGenV.generateTopics(keyAlg, keySize, timeout1, timeout2);
            connectorv.setEncryptedDataTopicUUID(stkGenV.topicUUIDData);
            connectorv.setEncryptedControlTopicUUID(stkGenV.topicUUIDControl);

            try {
                connectorv.initializeBrokerCommunications(props, commType);
                connectorv.initializeTransmitter(sig, mode, padding,
                        stkGenV.topicUUIDData, stkGenV.stkData,
                        stkGenV.topicUUIDControl, stkGenV.stkControl,
                        stkGenV.c_priv);
                // connector.initializeReceiver();
            } catch (ServiceException ex) {
                ex.printStackTrace();
            }
            ctv = new NBMediaTransmitter(connectorv);
            ctv.setDataSource(dataSourcev);
        }

        System.out.print("INIT DONE: Press a key to continue...");
        System.in.read();
        System.out.print("continuing...");

        if (enableAudio) {
            String resulta = cta.start();
            if (resulta != null) {
                System.err
                        .println("Failed to initialize the transmitter. The message   is: "
                                + resulta);
            } else {
                System.err
                        .println("  - Started transmitting data to the   topic: "
                                + topicNumber
                                + " at the broker "
                                + brokerIP
                                + ":" + brokerPort);
            }
        }

        if (enableVideo) {
            String resultv = ctv.start();
            if (resultv != null) {
                System.err
                        .println("Failed to initialize the transmitter. The message   is: "
                                + resultv);
            } else {
                System.err
                        .println("  - Started transmitting data to the   topic: "
                                + topicNumber
                                + " at the broker "
                                + brokerIP
                                + ":" + brokerPort);
            }
        }

        // wait indefinetely
        while (true) {
            try {
                Thread.sleep(10000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    } // end of main

    public static void printUsage() {
        System.out
                .println("Usage: java cgl.narada.samples.rtp.Transmitter  <Broker IP>   <Broker Port>   <Topic Number>");
    }

    /**
     * get a MediaLocator from a capture device for video
     */
    public static MediaLocator getMediaLocator() {
        VideoFormat videoFormat = new VideoFormat(VideoFormat.YUV);
        java.util.Vector deviceList = CaptureDeviceManager
                .getDeviceList(videoFormat);
        MediaLocator ml = null;
        if (deviceList.size() == 0) {
            System.out
                    .println("There is no video device on the computer or You did not run JMFRegistry");
            System.out
                    .println("if you had installed the JMF but did not run JMFRegistry, please run JMFRegistry and try again");
            System.out
                    .println("It is in the same folder as JMStudio in applications menu");
        } else if (deviceList.size() == 1) {
            ml = ((CaptureDeviceInfo) deviceList.get(0)).getLocator();
        } else {
            System.out
                    .println("There are more than one Video device on this machine.");
            System.out.println("We will try the first one");
            ml = ((CaptureDeviceInfo) deviceList.get(0)).getLocator();
        }
        return ml;
    }

    // HG: Added for security init
    private String topicName = "encrypted";
    private String topicUUID;
    private PrivateKey c1_priv;
    private String algo = null;
    private int keylen = -1;

    private EventProducer producer;

    SecureTopicKeyResponse resp;

}
